﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ROrganizer.Client;
using ROrganizer.Client.Files;
using ROrganizer.UI.Controllers.Core;

namespace ROrganizer.UI.Controllers
{
    internal class UpdateFormController
    {
        private readonly FastObservableCollection<Message> messages;
        private readonly AsyncWorker worker;
        private readonly FileProcessor.CollectDataMode flags;

        public UpdateFormController(bool hash, bool info, bool imdb, bool meta, Action<Exception> exceptioner = null)
        {
            this.messages = new FastObservableCollection<Message>();
            this.worker = new AsyncWorker(this.OnChanged, exceptioner: exceptioner);
            this.flags = FileProcessor.CollectDataMode.None;

            if (hash)
                this.flags |= FileProcessor.CollectDataMode.Hash;

            if (info)
                this.flags |= FileProcessor.CollectDataMode.Info;

            if (imdb)
                this.flags |= FileProcessor.CollectDataMode.Imdb;

            if (meta)
                this.flags |= FileProcessor.CollectDataMode.Meta;
        }

        public event EventHandler Changed;
        private void OnChanged()
        {
            if (this.Changed != null)
                this.Changed(this, EventArgs.Empty);
        }

        public ObservableCollection<Message> Messages
        {
            get { return this.messages; }
        }

        public bool IsChanged { get; private set; }
        public bool IsWorking
        {
            get { return this.worker.IsWorking; }
        }

        public void Start()
        {
            this.worker.Execute(this.OnStartCallback, exceptioner: this.OnStartCallbackExceptioner);
        }

        public bool CanStop()
        {
            return this.worker.CanStop;
        }

        public void Stop()
        {
            this.worker.Stop();
        }

        private void OnStartCallback()
        {
            var processor = new FileProcessor();
            var folders = ApplicationSettings.GetInstance().GetFolders();
            var files = FileEnumerator.EnumerateFiles(folders).ToArray();

            processor.Completed += this.OnProcessCompleted;
            files.AsParallel().WithDegreeOfParallelism(8).ForAll(file => processor.CollectData(file, this.flags));
        }

        private void OnProcessCompleted(object sender, FileProcessor.CompletedEventArgs e)
        {
            lock (this.messages)
            {
                this.messages.Add(new Message { Action = e.Operation.ToString().ToUpper(), Content = e.Path });
                this.IsChanged = true;
            }
        }

        private void OnStartCallbackExceptioner(Exception exception)
        {
            lock (this.messages)
            {
                while (exception != null)
                {
                    this.messages.Add(new Message { Content = exception.Message, Action = String.Empty });
                    exception = exception.InnerException;
                }
            }
        }

        public class Message
        {
            public string Content { get; set; }
            public string Action { get; set; }
        }
    }
}
